﻿#include "HellLord.h"
#include "../../MirEnvir/Envir.h"
#include "../../../Shared/ServerPackets.h"
#include "../SpellObject.h"
#include "../../../Shared/Data/Stat.h"
#include "../DelayedAction.h"
#include "HellKnight.h"
#include "../../../Shared/Functions/Functions.h"

using namespace Server::MirDatabase;
using namespace Server::MirEnvir;
namespace S = ServerPackets;

namespace Server::MirObjects::Monsters
{

    bool HellLord::getCanMove() const
    {
        return false;
    }

    bool HellLord::getCanRegen() const
    {
        return false;
    }

    HellLord::HellLord(MonsterInfo *info) : MonsterObject(info)
    {
        setDirection(MirDirection::Up);
        _begin = true;
    }

    bool HellLord::InAttackRange()
    {
        if (getTarget()->getCurrentMap() != getCurrentMap())
        {
            return false;
        }

        return true;
    }

    void HellLord::Turn(MirDirection dir)
    {
    }

    bool HellLord::Walk(MirDirection dir)
    {
        return false;
    }

    int HellLord::Attacked(MonsterObject *attacker, int damage, DefenceType type)
    {
        if (_stage >= 4)
        {
            return MonsterObject::Attacked(attacker, damage, type);
        }

        return 0;
    }

    int HellLord::Attacked(PlayerObject *attacker, int damage, DefenceType type, bool damageWeapon)
    {
        if (_stage >= 4)
        {
            return MonsterObject::Attacked(attacker, damage, type, damageWeapon);
        }

        return 0;
    }

    void HellLord::ApplyPoison(Poison *p, MapObject *Caster, bool NoResist, bool ignoreDefence)
    {

    }

    void HellLord::Process()
    {
        if (getCurrentMap()->Players.empty() && _stage > 0)
        {
            _stage = 0;
            _begin = true;
        }

        MonsterObject::Process();
    }

    void HellLord::ProcessTarget()
    {
        if (getCurrentMap()->Players.empty())
        {
            return;
        }

        if (!getCanAttack())
        {
            return;
        }

        if (_raged && _rageTime < getEnvir()->getTime() && _stage < 4 || _begin)
        {
            if (_begin)
            {
                _begin = false;
            }

            _raged = false;

            SpawnKnight();

            S::ObjectAttack *tempVar = new S::ObjectAttack();
            tempVar->ObjectID = ObjectID;
            tempVar->Direction = getDirection();
            tempVar->Location = getCurrentLocation();
            Broadcast(tempVar);

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
        }

        if (getEnvir()->Random->Next(_bombChance) == 0 || _raged)
        {
            SpawnBomb();
        }

        SpawnQuakes();

        ActionTime = getEnvir()->getTime() + 600;
        AttackTime = getEnvir()->getTime() + AttackSpeed;
    }

    void HellLord::Attack()
    {
    }

    void HellLord::SpawnQuakes()
    {
        int count = getEnvir()->Random->Next(1, _raged ? _quakeCount * 2 : _quakeCount);
        int distance = getEnvir()->Random->Next(_quakeSpreadMin, _quakeSpreadMax);

        for (int j = 0; j < getCurrentMap()->Players.size(); j++)
        {
            Point *playerLocation = getCurrentMap()->Players[j]->getCurrentLocation();

            for (int i = 0; i < count; i++)
            {
                Point *location = new Point(playerLocation->X + getEnvir()->Random->Next(-distance, distance + 1), playerLocation->Y + getEnvir()->Random->Next(-distance, distance + 1));

                if (getEnvir()->Random->Next(10) == 0)
                {
                    location = playerLocation;
                }

                if (!getCurrentMap()->ValidPoint(location))
                {
//C# TO C++ CONVERTER TODO TASK: A 'delete location' statement was not added since location was passed to a method or constructor. Handle memory management manually.
                    continue;
                }

                auto start = getEnvir()->Random->Next(5000);

                auto spellObj = new SpellObject();
                spellObj->Spell = getEnvir()->Random->Next(2) == 0 ? Spell::MapQuake1 : Spell::MapQuake2;
                spellObj->Value = getEnvir()->Random->Next(getEnvir()->Random->Next(Stats[Stat::MinDC], Stats[Stat::MaxDC]));
                spellObj->ExpireTime = getEnvir()->getTime() + 2000 + start;
                spellObj->TickSpeed = 500;
                spellObj->Caster = nullptr;
                spellObj->setCurrentLocation(location);
                spellObj->setCurrentMap(getCurrentMap());
                spellObj->setDirection(MirDirection::Up);

                DelayedAction *action = new DelayedAction(DelayedType::Spawn, getEnvir()->getTime() + start, {spellObj});
                getCurrentMap()->ActionList.push_back(action);

//C# TO C++ CONVERTER TODO TASK: A 'delete action' statement was not added since action was passed to a method or constructor. Handle memory management manually.
//C# TO C++ CONVERTER TODO TASK: A 'delete spellObj' statement was not added since spellObj was passed to a method or constructor. Handle memory management manually.
//C# TO C++ CONVERTER TODO TASK: A 'delete location' statement was not added since location was passed to a method or constructor. Handle memory management manually.
            }
        }

    }

    void HellLord::SpawnBomb()
    {
        int distance = getEnvir()->Random->Next(_bombSpreadMin, _bombSpreadMax);

        for (int j = 0; j < getCurrentMap()->Players.size(); j++)
        {
            Point *playerLocation = getCurrentMap()->Players[j]->getCurrentLocation();

            Point *location = new Point(playerLocation->X + getEnvir()->Random->Next(-distance, distance + 1), playerLocation->Y + getEnvir()->Random->Next(-distance, distance + 1));

            MonsterObject *mob = nullptr;
            switch (getEnvir()->Random->Next(3))
            {
                case 0:
                    mob = GetMonster(getEnvir()->GetMonsterInfo(Settings::HellBomb1));

                    delete location;
                    break;
                case 1:
                    mob = GetMonster(getEnvir()->GetMonsterInfo(Settings::HellBomb2));
                    break;
                case 2:
                    mob = GetMonster(getEnvir()->GetMonsterInfo(Settings::HellBomb3));
                    break;
            }

            if (mob == nullptr)
            {
                delete location;
                return;
            }

            mob->Spawn(getCurrentMap(), location);

//C# TO C++ CONVERTER TODO TASK: A 'delete location' statement was not added since location was passed to a method or constructor. Handle memory management manually.
        }
    }

    void HellLord::SpawnKnight()
    {
        MonsterObject *mob = nullptr;

        switch (_stage)
        {
            case 0:
                mob = GetMonster(getEnvir()->GetMonsterInfo(Settings::HellKnight1));
                break;
            case 1:
                mob = GetMonster(getEnvir()->GetMonsterInfo(Settings::HellKnight2));
                break;
            case 2:
                mob = GetMonster(getEnvir()->GetMonsterInfo(Settings::HellKnight3));
                break;
            case 3:
                mob = GetMonster(getEnvir()->GetMonsterInfo(Settings::HellKnight4));
                break;
        }

        if (mob == nullptr || !(dynamic_cast<HellKnight*>(mob) != nullptr))
        {
            return;
        }

        HellKnight *knight = static_cast<HellKnight*>(mob);
        knight->Owner = this;
        knight->Lord = this;

        Point *front = Functions::PointMove(getCurrentLocation(), MirDirection::DownLeft, 12);

        for (int i = 0; i < 50; i++)
        {
            Point *location = new Point(front->X + getEnvir()->Random->Next(-10, 10), front->Y + getEnvir()->Random->Next(-10, 10));

            if (getCurrentMap()->ValidPoint(location))
            {
                DelayedAction *action = new DelayedAction(DelayedType::Spawn, getEnvir()->getTime() + 500, {knight, location});
                getCurrentMap()->ActionList.push_back(action);

//C# TO C++ CONVERTER TODO TASK: A 'delete action' statement was not added since action was passed to a method or constructor. Handle memory management manually.
//C# TO C++ CONVERTER TODO TASK: A 'delete location' statement was not added since location was passed to a method or constructor. Handle memory management manually.
                break;

//C# TO C++ CONVERTER TODO TASK: A 'delete action' statement was not added since action was passed to a method or constructor. Handle memory management manually.
            }

//C# TO C++ CONVERTER TODO TASK: A 'delete location' statement was not added since location was passed to a method or constructor. Handle memory management manually.
        }
    }

    void HellLord::KnightKilled()
    {
        _rageTime = getEnvir()->getTime() + _rageDelay;
        _raged = true;

        _stage += 1;

        Broadcast(GetInfo());
    }

    Packet *HellLord::GetInfo()
    {
        S::ObjectMonster *tempVar = new S::ObjectMonster();
        tempVar->ObjectID = ObjectID;
        tempVar->Name = getName();
        tempVar->NameColour = NameColour;
        tempVar->Location = getCurrentLocation();
        tempVar->Image = Info->Image;
        tempVar->Direction = getDirection();
        tempVar->Effect = Info->Effect;
        tempVar->AI = Info->AI;
        tempVar->Light = Info->Light;
        tempVar->Dead = Dead;
        tempVar->Skeleton = Harvested;
        tempVar->Poison = CurrentPoison;
        tempVar->Hidden = getHidden();
        tempVar->ExtraByte = _stage;

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was used in a 'return' or 'throw' statement.
        return tempVar;
    }
}
